home *** CD-ROM | disk | FTP | other *** search
- /*
- ild: incremental linker/loader on System V
-
- (C) Masami Hagiya, 1986
- UTS version (C) Akiumi Hasegawa, 1987
-
- Usage:
- % ild loading_object start_address \
- loaded_object output_file
-
- The start address is in decimal.
-
- How to Create:
-
- To compile this file (ild.c) and make ild, do the following.
-
- % cc -o ild ild.c -lld
-
-
- Problem:
- This program only supports the simplest linear search for symbols.
-
- This program is modified for UTS system.
-
- */
-
- #include <stdio.h>
- #include <filehdr.h>
- #include <aouthdr.h>
- #include <scnhdr.h>
- #include <reloc.h>
- #include <syms.h>
- #include <storclass.h>
- #include <ldfcn.h>
-
- struct filehdr my_header;
- struct syment *my_symbol_table;
- char *my_string_table;
-
- struct filehdr header;
- struct aouthdr opt_header;
- struct scnhdr section[9];
- char *text;
- struct syment *symbol_table;
- char *string_table;
-
- char *start_address;
-
- struct reloc relocation_info;
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- if (argc < 5) {
- fprintf(stderr, "Arg count.\n");
- exit(1);
- }
-
- #ifdef DEBUG
- printf("ild %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4]);
- fflush(stdout);
- #endif
-
- get_myself(argv[1]);
- start_address = (char *)atoi(argv[2]);
-
- #ifdef DEBUG
- printf("start address= %x\n",(int)start_address);fflush(stdout);
- #endif
-
- fasload(argv[3], argv[4]);
- exit(0);
- }
-
- get_myself(filename)
- char *filename;
- {
- int i;
- LDFILE *ldptr;
- extern char *malloc();
- ldptr = ldopen(filename, NULL);
- if (ldptr == NULL) {
- fprintf(stderr, "Can't open %s\n", filename);
- exit(1);
- }
-
- ldfhread(ldptr, &my_header);
-
- ldtbseek(ldptr);
- my_symbol_table
- = (struct syment *)malloc(sizeof(struct syment) * my_header.f_nsyms);
-
- /*
- sizeof(struct syment) and SYMESZ are not always the same.
- */
-
- if(my_symbol_table == NULL){
- fprintf(stderr,"Can't allocate memory for my_symbol_table\n");
- exit(1);
- }
- for (i = 0; i < my_header.f_nsyms; i++)
- FREAD(&my_symbol_table[i], SYMESZ, 1, ldptr);
-
- /*
- If the string table is not empty,
- its length is stored after the symbol table,
- This is described in the manual.
- (see UTS Support Tools Guide V10L20)
- */
-
- if (FREAD(&i, 4, 1, ldptr) > 0) {
- my_string_table = malloc(i);
- FSEEK(ldptr, -4, 1);
- FREAD(my_string_table, 1, i, ldptr);
- }
-
- ldclose(ldptr);
- }
-
- fasload(filename, outputfilename)
- char *filename, *outputfilename;
- {
- register struct syment *sym, *end;
- int i, n;
- LDFILE *ldptr;
- FILE *fp;
-
- extern char *malloc();
-
- ldptr = ldopen(filename, "r");
- if (ldptr == NULL) {
- fprintf(stderr, "Can't open %s\n", filename);
- exit(1);
- }
-
- ldfhread(ldptr, &header);
-
- FREAD(&opt_header,sizeof(struct aouthdr),1,ldptr);
-
- if (header.f_nscns < 3 || header.f_nscns > 8) {
- fprintf(stderr, "Illegal number of sections.\n");
- exit(1);
- }
-
- for (i = 1; i <= header.f_nscns; i++)
- ldshread(ldptr, i, §ion[i]);
-
- if (strcmp(section[1].s_name, ".text") != 0) {
- fprintf(stderr, ".text not found.\n");
- exit(1);
- }
- if (strcmp(section[2].s_name, ".data") != 0) {
- fprintf(stderr, ".data not found.\n");
- exit(1);
- }
- /*
- The bss segment need not exist.
- */
- /*
- if (strcmp(section[3].s_name, ".bss") != 0) {
- fprintf(stderr, ".bss not found.\n");
- exit(1);
- }
- */
-
- if (section[1].s_size > 0 &&
- section[1].s_scnptr !=
- sizeof(struct filehdr) + sizeof(struct aouthdr) +
- header.f_nscns*sizeof(struct scnhdr)) {
- fprintf(stderr, "Contradictory text start.\n");
- exit(1);
- }
- if (section[1].s_size > 0 && section[2].s_size > 0 &&
- section[1].s_scnptr + section[1].s_size !=
- section[2].s_scnptr) {
- fprintf(stderr, "Contradictory data start.\n");
- exit(1);
- }
-
- text = malloc(section[1].s_size + section[2].s_size);
-
- FSEEK(ldptr, section[1].s_scnptr, 0);
- FREAD(text, 1, section[1].s_size + section[2].s_size, ldptr);
-
- ldtbseek(ldptr);
- symbol_table
- = (struct syment *)malloc(sizeof(struct syment) * header.f_nsyms);
- /*
- sizeof(struct syment) and SYMESZ are not always the same.
- */
- for (i = 0; i < header.f_nsyms; i++)
- FREAD(&symbol_table[i], SYMESZ, 1, ldptr);
- /*
- If the string table is not empty,
- its length is stored after the symbol table,
- This is described in the manual.
- (see UTS Support Tools Guide V10L20)
- */
-
- if (FREAD(&i, 4, 1, ldptr) > 0) {
- string_table = malloc(i);
- FSEEK(ldptr, -4, 1);
- FREAD(string_table, 1, i, ldptr);
- }
-
- end = symbol_table + header.f_nsyms;
- for (sym = symbol_table; sym < end; sym++) {
- switch (sym->n_scnum) {
- /* in UTS, relocatable address is the offset in the
- section, in which it defined.
- Thus "sym->n_value" for each section should be
- the the top address of the section.
- in case of ".data" section, s_vaddr is equal to
- s_size. However, ".bss" section, s_vaddr <>
- textsize+datasize. I cannot understand why. But
- this code works well.
- */
- case 1:
- /* .text */
- sym->n_value = (int)start_address; break;
- case 2:
- /* .data */
- sym->n_value = (int)start_address + section[1].s_size;
- break;
- case 3:
- /* .bss */
- sym->n_value = (int)start_address + section[1].s_size
- + section[2].s_size;
- break;
-
- case N_UNDEF:
- search_symbol(sym);
- break;
- default:
- /*
- Does nothing. Is it OK?
- */
- break;
- }
- sym += sym->n_numaux;
- }
-
- if(ldrseek(ldptr, 1) ==FAILURE){
- fprintf(stderr,"Can't locate relocation table\n");
- exit(1);
- }
- for (i=0; i< section[1].s_nreloc; i++){
- FREAD(&relocation_info,10,1,ldptr);
- relocate();
- }
-
- ldrseek(ldptr, 2);
- for (i = 0; i < section[2].s_nreloc; i++) {
- FREAD(&relocation_info, 10, 1, ldptr);
- relocate();
- }
-
- fp = fopen(outputfilename, "w");
- if (fp == NULL) {
- fprintf(stderr, "Can't creat %s.\n", outputfilename);
- exit(1);
- }
- fwrite(&header, sizeof(struct filehdr), 1, fp);
- fwrite(&opt_header,sizeof(struct aouthdr),1,fp);
- for (i = 1; i<= header.f_nscns; i++)
- fwrite(§ion[i], sizeof(struct scnhdr), 1, fp);
- fwrite(text, 1, section[1].s_size + section[2].s_size, fp);
-
- fclose(fp);
- ldclose(ldptr);
- }
-
- search_symbol(sym)
- register struct syment *sym;
- {
- register struct syment *p, *end;
- end = my_symbol_table + my_header.f_nsyms;
- for (p = my_symbol_table; p < end; p++) {
- /*
- Is the following check enough?
- */
- if (1 <= p->n_scnum && p->n_scnum <= 3 &&
- p->n_sclass == C_EXT &&
- (sym->n_zeroes == 0
- ? (p->n_zeroes == 0 &&
- strcmp(&my_string_table[p->n_offset],
- &string_table[sym->n_offset]) == 0)
- : (p->n_zeroes != 0 &&
- strncmp(p->n_name, sym->n_name, SYMNMLEN) == 0)))
- goto FOUND;
- p += p->n_numaux;
- }
-
- sym->n_name[SYMNMLEN] = '\0';
- fprintf(stderr, "%s: undefined symbol.\n",
- (sym->n_zeroes ? sym->n_name : &string_table[sym->n_offset]));
- exit(1);
-
- FOUND:
- sym->n_value = p->n_value;
- }
-
- relocate()
- {
- char *where, *p;
- int value;
-
- where = text + relocation_info.r_vaddr;
- if (relocation_info.r_type == R_ABS)
- return;
- /*
- The following code depends on CPU.
- in case of UTS, R_RELLONG is assumed.
- */
- if (relocation_info.r_type != R_RELLONG) {
- fprintf(stderr, "%d: unsupported relocation type.",
- relocation_info.r_type);
- exit(1);
- }
- /*
- Assuming R_RELLONG.
- */
- p = (char *)(&value);
- p[0] = where[0];
- p[1] = where[1];
- p[2] = where[2];
- p[3] = where[3];
-
- #ifdef DEBUG
- printf("%s\n",
- (symbol_table[relocation_info.r_symndx].n_zeroes ?
- symbol_table[relocation_info.r_symndx].n_name :
- &string_table
- [symbol_table[relocation_info.r_symndx].n_offset]));
- printf("value = %x\n",value);fflush(stdout);
- #endif
-
- value += symbol_table[relocation_info.r_symndx].n_value;
-
- #ifdef DEBUG
- printf("value = %x\n",value);fflush(stdout);
- #endif
-
- where[0] = p[0];
- where[1] = p[1];
- where[2] = p[2];
- where[3] = p[3];
- }
-